#pragma once
#include "mq_exchange.hpp"
#include "mq_queue.hpp"
#include "mq_binding.hpp"
#include "mq_message.hpp"

namespace ns_kkymq
{
    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;
        VirtualHost(const std::string &h_name, const std::string &basedir, const std::string &dbfile)
            : _host_name(h_name), _emp(std::make_shared<ExchangeManager>(dbfile)), _mqmp(std::make_shared<MsgQueueManager>(dbfile)), _bmp(std::make_shared<BindingManager>(dbfile)), _mmp(std::make_shared<MessageManager>(basedir))
        {
            // 获取到所有的队列信息，通过队列名称恢复历史消息数据
            QueueMap qm = _mqmp->allQueues();
            for (auto &q : qm)
            {
                _mmp->initQueueMessage(q.first);
            }
        }
        bool declareExchange(const std::string &name, ExchangeType type, bool durable,
                             bool auto_delete, const google::protobuf::Map<std::string, std::string> &args)
        {
            return _emp->declareExchange(name, type, durable, auto_delete, args);
        }

        void deleteExchange(const std::string &name)
        {
            // 删除交换机的时候，需要将交换机相关的绑定信息也删除掉。
            _bmp->removeExchangeBindings(name);
            _emp->deleteExchange(name);
        }

        Exchange::ptr selectExchange(const std::string& name)
        {
            return _emp->selectExchange(name);
        }

        bool existsExchange(const std::string &name)
        {
            return _emp->exists(name);
        } 

        bool declareQueue(const std::string &name, bool durable, bool exclusive, bool auto_delete,
                          const google::protobuf::Map<std::string, std::string> &args)
        {
            // 初始化队列的消息句柄（消息的存储管理）
            // 队列的创建
            _mmp->initQueueMessage(name);
            return _mqmp->declareQueue(name, durable, exclusive, auto_delete, args);
        }

        void deleteQueue(const std::string &name)
        {
            // 删除的时候队列相关的数据有两个：队列的消息，队列的绑定信息
            _mmp->destroyQueueMessage(name);
            _bmp->removeMagQueueBindings(name);
            _mqmp->deleteQueue(name);
        }

        bool existsQueue(const std::string &name)
        {
            return _mqmp->exists(name);
        } 

        QueueMap allQueues()
        {
            return _mqmp->allQueues();
        }

        bool bind(const std::string &e_name, const std::string &q_name, const std::string key)
        {
            Exchange::ptr ep = _emp->selectExchange(e_name);
            if (ep.get() == nullptr)
            {
                lg(Info, "进行队列绑定失败,交换机%s不存在!", e_name.c_str());
                return false;
            }
            MsgQueue::ptr mqp = _mqmp->selectQueue(q_name);
            if (mqp.get() == nullptr)
            {
                lg(Info, "进行队列绑定失败,队列%s不存在!", q_name.c_str());
                return false;
            }
            return _bmp->bind(e_name, q_name, key, ep->_durable && mqp->_durable);
        }

        void unBind(const std::string &e_name, const std::string &q_name)
        {
            return _bmp->unBind(e_name, q_name);
        }

        bool existsBinding(const std::string &e_name, const std::string &q_name)
        {
            return _bmp->exists(e_name,q_name);
        }

        MsgQueueBindingMap exchangeBindings(const std::string e_name)
        {
            return _bmp->getExchangeBindings(e_name);
        }

        bool basicPublish(const std::string &q_name, BasicProperties *bp, const std::string &body)
        {
            MsgQueue::ptr mqp = _mqmp->selectQueue(q_name);
            if (mqp.get() == nullptr)
            {
                lg(Info, "发布消息失败,队列%s不存在!", q_name.c_str());
                return false;
            }
            return _mmp->insert(q_name, bp, body, mqp->_durable);
        }

        MessagePtr basicComsume(const std::string &q_name)
        {
            return _mmp->front(q_name);
        }

        void basicAck(const std::string &q_name, const std::string &msgid)
        {
            _mmp->ack(q_name, msgid);
        }

        void clear()
        {
            _emp->clear();
            _mqmp->clear();
            _bmp->clear();
            _mmp->clear();
        }

    private:
        std::string _host_name;
        ExchangeManager::ptr _emp;
        MsgQueueManager::ptr _mqmp;
        BindingManager::ptr _bmp;
        MessageManager::ptr _mmp;
    };
}